En esta secci\'{o}n detallaremos qu\'{e} estructuras definimos y c\'{o}mo las completamos para activar la unidad de segmentaci\'{o}n para, posteriormente, 
pasar el modo del procesador de real a protegido. La unidad de segmentaci\'{o}n se 
encargar\'{a} de hacer la traducci\'{o}n de una direcci\'{o}n l\'{o}gica, es decir, una direcci\'{o}n escrita en la forma segmento:offset dentro del segmento 
(codificaci\'{o}n que utilizamos en los programas escritos en lenguaje ensamblador) a una direcci\'{o}n lineal. Como aclaraci\'{o}n, un segmento no es m\'{a}s
que un bloque de memoria consecutiva.

Por uno de los requerimientos del enunciado, debimos definir, en principio, 4 segmentos, donde dos de ellos eran para c\'{o}digo y los otros dos para datos 
(uno con nivel de acceso 0 y el otro con nivel 3 para cada uno de los tipos de segmento). Adem\'{a}s, el enunciado requer\'{i}a que el primer \'{i}ndice 
fuera el 8 (contando desde cero), con lo cual, nuestra tabla de descriptores globales (GDT) tiene, en la posici\'{o}n 0, el descriptor nulo (obligatorio para
la arquitectura en que estamos trabajando), seguido por 7 entradas vac\'{i}as y, a partir de la octava entrada, comienzan los segmentos definidos por
nosotros. A continuaci\'{o}n, explicaremos c\'{o}mo completamos la GDT para completar cada uno de los items del ejercicio 1, adem\'{a}s de algunas rutinas 
extra, necesarias para pasar el procesador a modo protegido o pintar la pantalla.

\subsection{Inciso a}

En este inciso, el enunciado ped\'{i}a definir 4 segmentos en la GDT: dos destinados a c\'{o}digo de nivel 0 y 3, y dos destinados a datos de nivel 0 y 3.
Arbitrariamente, decidimos definirlos en el siguiente orden dentro de la tabla: 

gdt[8] = C\'{o}digo de nivel 0 (nivel de privilegio kernel).

gdt[9] = C\'{o}digo de nivel 3 (nivel de privilegio usuario).

gdt[10] = Datos nivel kernel.

gdt[11] = Datos nivel usuario.

Recordamos que la tabla GDT no es m\'{a}s que un arreglo de elementos de tipo gdt entry, donde el struct gdt entry est\'{a} definido de la siguiente manera:

\begin{codesnippet}
\begin{verbatim}
typedef struct str_gdt_entry {
    unsigned short  limit_0_15;
    unsigned short  base_0_15;
    unsigned char   base_23_16;
    unsigned char   type:4;
    unsigned char   s:1;
    unsigned char   dpl:2;
    unsigned char   p:1;
    unsigned char   limit_16_19:4;
    unsigned char   avl:1;
    unsigned char   l:1;
    unsigned char   db:1;
    unsigned char   g:1;
    unsigned char   base_31_24;
} __attribute__((__packed__, aligned (8))) gdt_entry;
\end{verbatim}
\end{codesnippet}

As\'{i}, lo \'{u}nico que resta es explicar c\'{o}mo completamos los campos de cada una de las 4 entradas para que cumplieran los requerimientos del 
enunciado.

Vale la pena se\~{n}alar que muchos de los campos son id\'{e}nticos en las 4 entradas (como por ejemplo los de limite y base, pues los 4 segmentos de este 
inciso deben direccionar los primeros 623MB de la memoria), con lo cual explicaremos, en primer lugar, los campos cuya informaci\'{o}n es id\'{e}ntica
para todos los segmentos, y luego explicaremos individualmente aquellos donde no lo sea.

Ya hemos dicho que la base y el l\'{i}mite es el mismo para los 4 segmentos. En efecto, como deben direccionar los primeros 623MB de memoria, el campo 
base estar\'{a} en 0, pues la base indica, justamente, donde empieza el segmento. El campo l\'{i}mite indica cu\'{a}l es el m\'{a}ximo offset 
permitido dentro de un segmento; as\'{i}, por ejemplo, un segmento que mida 1 byte tendr\'{a} l\'{i}mite 0.

Para explicar c\'{o}mo completamos el campo l\'{i}mite, es oportuno explicar
primero c\'{o}mo funciona el campo granularity (g). Este campo definir\'{a} de a cu\'{a}ntos bytes aumentar\'{a} el tama\~{n}o del segmento al incrementar en una 
unidad el campo l\'{i}mite: si granularity = 0, incrementar en uno el campo l\'{i}mite da lugar a un incremento en un byte en el tama\~{n}o del segmento; si, por
el contrario, granularity = 1, incrementar en una unidad el l\'{i}mite aumentar\'{a} en 4KB el tama\~{n}o del segmento. En nuestro caso, decidimos poner g = 1,
pues deb\'{i}amos direccionar 623MB de memoria y era posible que no nos alcanzaran los 20 bits que tiene en total el campo limite para asignarle ese tama\~{n}o
a los segmentos. Con esto en mente, el c\'{a}lculo del l\'{i}mite para los segmentos es el siguiente:

\begin{equation*}
 \frac{623MB}{4K} - 1 = 0x26EFF
\end{equation*}

con lo cual, en las 4 entradas, los dos pedazos del campo l\'{i}mite quedaron as\'{i}:

\begin{codesnippet}
\begin{verbatim}
  limit_0_15 = 0x6EFF;
  limit_16_19 = 0x02;
\end{verbatim}
\end{codesnippet}

Otro de los campos iguales para las 4 entradas es el s (system). Este campo estar\'{a} en 0 cuando el segmento sea de sistema, y en 1 cuando sea de 
c\'{o}digo o de datos, con lo cual los 4 segmentos tienen dicho campo seteado en 1. Obviamente, como queremos que todos los segmentos esten marcados
como presentes, seteamos el bit p (presente) en 1. Como deseamos pasar a modo protegido y trabajar en 32 bits, funcionalidad manejada por el campo
d/b, seteamos en 1 dicho campo. Por la misma raz\'{o}n, como el campo l indica si es un segmento de 64 bits o no, pusimos ese campo en 0 para indicar
que no lo es. En todos los campos, seteamos el campo avl (available for system software) en 1. (%TODO: explicar por qué)

Respecto del campo DPL (descriptor privilege level), aclaramos que este indica qu\'{e} nivel de privilegio se debe tener para acceder al segmento, siendo
0 el m\'{a}s privilegiado y 3 el menos privilegiado. Esto implica que el campo DPL estar\'{a} seteado en 0 en los segmentos de c\'{o}digo y datos de nivel 0,
y en 3 en segmentos de c\'{o}digo y datos de nivel 3.

S\'{o}lo resta explica el campo t (type), el cual estar\'{a} completado de manera distinta para cada una de las 4 entradas de este ejercicio, seg\'{u}n el 
segmento sea de c\'{o}digo o de datos. Para los dos segmentos de datos (nivel 0 y 3), el campo type est\'{a} seteado en el valor $0x2$, el cual corresponde
a la descripci\'{o}n de un segmento de datos con permisos para lectura y para escritura. Para los dos segmentos de c\'{o}digo, completamos el campo type 
con el valor $0xA$, que describe un segmento de c\'{o}digo con permisos para ejecutar y para leer su contenido. 
Para m\'{a}s detalle respecto de los tipos de segmentos disponibles, puede consultarse el volumen 2 del manual de Intel.

\subsection{Inciso b}

Una vez completadas las 4 entradas del inciso anterior, debemos completar algunos pasos m\'{a}s para pasar a modo protegido. En primer lugar, debemos 
cargar el registro GDTR con un valor de 6 bytes, donde los primeros 2 bytes indican el tama\~{n}o de nuestra tabla GDT, y los siguientes 4 bytes indican la
posici\'{o}n en memoria de dicha tabla. Para para poder cargar esa estructura en el registro GDTR, nos valimos del struct gdt descriptor provisto por 
la c\'{a}tedra: 

\begin{codesnippet}
\begin{verbatim}
  typedef struct str_gdt_descriptor {
    unsigned short  gdt_length;
    unsigned int    gdt_addr;
} __attribute__((__packed__)) gdt_descriptor;
\end{verbatim}
\end{codesnippet}

para definir una variable de ese tipo de la siguiente manera: 

\begin{codesnippet}
\begin{verbatim}
gdt_descriptor GDT_DESC = {
    sizeof(gdt) - 1,
    (unsigned int) &gdt
};
\end{verbatim}
\end{codesnippet}

y, por \'{u}ltimo, utilizar la siguiente instrucci\'{o}n:
\begin{codesnippet}
\begin{verbatim}
  LGDT [GDT_DESC]
\end{verbatim}
\end{codesnippet}
para cargar el registro GDTR con la estructura GDT DESC.

Una vez hecho esto, el siguiente paso es setear en 1 el bit menos significativo del registro de control CR0 (bit PE, por protected environment), que se puede
hacer de manera sencilla con las siguientes instrucciones: 
\begin{codesnippet}
\begin{verbatim}
  mov eax, cr0
  or eax, 1
  mov cr0, eax
\end{verbatim}
\end{codesnippet}

Una vez hecho todo esto, ya estamos listos para pasar a modo protegido. Para hacer esto, debemos indicarle al procesador que debe empezar a correr
en un segmento de c\'{o}digo de nivel 0 (es decir, poner en el selector de segmento de c\'{o}digo CS el valor de un descriptor de segmento 
correspondiente a un segmento de nivel kernel) y, adem\'{a}s, setear el registro EIP en la pr\'{o}xima instrucci\'{o}n a ejecutarse, lo cual 
puede hacerse mediante la instrucci\'{o}n jmp far. Recordamos que un selector de segmento es un n\'{u}mero de dos bytes con el siguiente formato:
\begin{verbatim}
|index|ti=0|rpl|
\end{verbatim}
donde index es un numero de 5 bits que indica el \'{i}ndice en la GDT del segmento, ti indica si es un segmento de la gdt o de la ldt (como no usaremos la 
ldt, siempre estar\'{a} en 0) y rpl (por requested privilege level) indica el privilegio con el cual se est\'{a} accediendo al segmento.
Si recordamos que nuestro segmento de c\'{o}digo nivel 0 est\'{a} en la octava entrada de la GDT, y que queremos accederlo desde el kernel,
el selector de segmento nos queda en el valor $01000 0 00 = 0x40$. Para completar la direcci\'{o}n l\'{o}gica a la cual hay que saltar, basta 
con poner una etiqueta en la l\'{i}nea siguiente al jmp far, con lo cual, la rutina para saltar a modo protegido queda as\'{i}:
\begin{codesnippet}
\begin{verbatim}
  jmp 0x40:modo_p
  BITS 32
  modo_p:
\end{verbatim}
\end{codesnippet}

Poner la pila en la direcci\'{o}n 0x27000 consiste, simplemente, en ponerle el valor 0x27000 al registro esp.

